package com.yx.changdao.web.config.shiro;

import com.yx.changdao.service.SysUserService;
import com.yx.changdao.web.config.shiro.filter.JwtAuthFilter;
import com.yx.changdao.web.config.shiro.realm.JWTShiroRealm;
import com.yx.changdao.web.config.shiro.realm.SysLoginRealm;
import org.apache.shiro.authc.Authenticator;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SessionStorageEvaluator;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSessionStorageEvaluator;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;

/**
 * shiro配置
 *
 * @author wangzd
 * @createtime 2019-11-04 13:08
 */
@Configuration
public class ShiroConfig {

    // 用户服务
    @Autowired
    private SysUserService userService;

    @Bean
    public FilterRegistrationBean<Filter> filterRegistrationBean(SecurityManager securityManager) throws Exception {
        FilterRegistrationBean<Filter> filterRegistration = new FilterRegistrationBean<Filter>();
        filterRegistration.setFilter((Filter) Objects.requireNonNull(shiroFilter(securityManager).getObject()));
        filterRegistration.addInitParameter("targetFilterLifecycle", "true");
        filterRegistration.setAsyncSupported(true);
        filterRegistration.setEnabled(true);
        filterRegistration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
        return filterRegistration;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
                = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    @Bean
    public Authenticator authenticator() {
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        authenticator.setRealms(Arrays.asList(sysLoginRealm(), jwtShiroRealm()));
        authenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
        return authenticator;
    }

    @Bean
    protected SessionStorageEvaluator sessionStorageEvaluator() {
        DefaultWebSessionStorageEvaluator sessionStorageEvaluator = new DefaultWebSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        return sessionStorageEvaluator;
    }

    @Bean
    public Realm sysLoginRealm() {
        return new SysLoginRealm();
    }

    @Bean
    public Realm jwtShiroRealm() {
        return new JWTShiroRealm();
    }

    /**
     * 设置过滤器
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        Map<String, Filter> filterMap = factoryBean.getFilters();
        filterMap.put("authcToken", createAuthFilter());
//        filterMap.put("anyRole", createRolesFilter());
        factoryBean.setFilters(filterMap);
        factoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition().getFilterChainMap());
        //
        factoryBean.setLoginUrl("/login");
        return factoryBean;
    }

    @Bean
    protected ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
        chainDefinition.addPathDefinition("/login", "noSessionCreation,anon");
        chainDefinition.addPathDefinition("/userinfo", "noSessionCreation,anon");

        chainDefinition.addPathDefinition("/verification", "noSessionCreation,anon");
        chainDefinition.addPathDefinition("/image/**", "anon");

        /**
         * 开发模板下载
         */
        chainDefinition.addPathDefinition("/problem/input/template", "anon");
        chainDefinition.addPathDefinition("/community/build/template", "anon");
        chainDefinition.addPathDefinition("/community/build/templateShop", "anon");
        chainDefinition.addPathDefinition("/community/resident/template", "anon");
        chainDefinition.addPathDefinition("/community/build/detail/template", "anon");

        chainDefinition.addPathDefinition("/community/build/down", "anon");
        chainDefinition.addPathDefinition("/grid/info/down", "anon");
        chainDefinition.addPathDefinition("/problem/assign/export/**", "anon");

        chainDefinition.addPathDefinition("/word/export/buildDetail/export", "anon");
        chainDefinition.addPathDefinition("/word/export/jbd/export/**", "anon");
        chainDefinition.addPathDefinition("/word/export/bjd/export/**", "anon");
        chainDefinition.addPathDefinition("/word/export/jbd/search/export/**", "anon");
        chainDefinition.addPathDefinition("/word/export/bjd/search/export/**", "anon");
        chainDefinition.addPathDefinition("/word/export/execute/jbd/search/export", "anon");
        chainDefinition.addPathDefinition("/word/export/assign/jbd/export", "anon");


        chainDefinition.addPathDefinition("/problem/overdue/export/**", "anon");
        chainDefinition.addPathDefinition("/problem/score/export/**", "anon");
        chainDefinition.addPathDefinition("/problem/score/modify/export/**", "anon");
        chainDefinition.addPathDefinition("/problem/difficult/export", "anon");

        chainDefinition.addPathDefinition("/problem/input/export/**", "anon");

        //全部路由
       // chainDefinition.addPathDefinition("/sys/menu/menus/**", "anon");

        chainDefinition.addPathDefinition("/admin/**", "noSessionCreation,authcToken"); /*,anyRole[admin,manager]*///只允许admin或manager角色的用户访问
        chainDefinition.addPathDefinition("/article/list", "noSessionCreation,authcToken");
        chainDefinition.addPathDefinition("/article/*", "noSessionCreation,authcToken[permissive]");
        chainDefinition.addPathDefinition("/**", "noSessionCreation,authcToken");
        return chainDefinition;
    }

    protected JwtAuthFilter createAuthFilter() {
        return new JwtAuthFilter(userService);
    }


    /**
     * 密码加密算法
     *
     * @return
     */
    @Bean("hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        // 散列的次数，比如散列两次，相当于md5(md5(""));
        hashedCredentialsMatcher.setHashIterations(10);
        return hashedCredentialsMatcher;
    }

}
